#pragma once
#include "Sock.hpp"
#include "Protocol.hpp"
#include <iostream>
#include <functional>
#include <pthread.h>

namespace tcpserver_ns
{
    using namespace protocol_ns;

    using func_t = std::function<Response(const Request &)>;

    class TcpServer;
    class ThreadData
    {
    public:
        ThreadData(int sock, std::string ip, uint16_t port, TcpServer *tsvrp)
            : _sock(sock), _ip(ip), _port(port), _tsvrp(tsvrp)
        {
            logMessage(DEBUG, "ThreadData::_tsvrp: %p", _tsvrp);
        }
        ~ThreadData() {}

    public:
        int _sock;
        std::string _ip;
        uint16_t _port;
        TcpServer *_tsvrp;
    };

    class TcpServer
    {
    public:
        TcpServer(func_t func, uint16_t port)
            : _port(port), _func(func)
        {
            logMessage(DEBUG, "TcpServer::this: %p, Port:%d", this, _port);
        }
        ~TcpServer() 
        {
            _listensock.Close();
        }
        void InitServer()
        {
            _listensock.Socket();
            _listensock.Bind(_port);
            _listensock.Listen();
            logMessage(INFO, "Init server done. Listensock: %d", _listensock.Fd());
        }
        void Start()
        {
            // 循环Accept
            for (;;)
            {
                std::string clientip;
                uint16_t clientport;

                logMessage(DEBUG, "正在Accept!");

                int sock = _listensock.Accept(&clientip, &clientport);
                if (sock < 0)
                    continue;
                logMessage(DEBUG, "Accept a new client: [%s-%d]", clientip.c_str(), clientport);

                pthread_t tid;
                ThreadData *td = new ThreadData(sock, clientip, clientport, this);
                pthread_create(&tid, nullptr, ThreadRoutine, td);
            }
        }
        static void *ThreadRoutine(void *args)
        {
            pthread_detach(pthread_self());
            ThreadData *td = static_cast<ThreadData *>(args);

            logMessage(DEBUG, "Thread running......");
            td->_tsvrp->ServiceIO(td->_sock, td->_ip, td->_port);

            delete td;
            return nullptr;
        }

        // 该函数被多线程调用
        // 客户端给服务器发送Request，服务器回复Response
        void ServiceIO(int sock, const std::string &ip, const uint16_t &port)
        {
            logMessage(DEBUG, " ServiceIO......");

            std::string inbuffer;
            while (true)
            {
                // 1.read/recv ------ 如何正确地读? 继续设计协议，添加报头和有效载荷，保证获得完整的字符串"10 + 20"
                // tcp面向字节流，能保证读到的就是一个完整的字符串例如"10 + 20" ？ 不能!
                // 要一直循环读取，边读取，边检测，去报头
                std::string package;
                int n = ReadPackage(sock, inbuffer, &package);
                if (n == -1)
                    break;
                else if (n == 0)
                    continue;
                else
                {
                    // 此时得到了完整报文

                    package = RemoveHeader(package, n);

                    // 2.读取到客户端发来的请求字符串，对字符串进行反序列化
                    Request req;
                    req.Deserialize(package);

                    // 3.提取客户端的请求，进行业务处理之后形成响应
                    Response resp = _func(req);

                    // 4.对Response结构进行序列化
                    std::string send_string;
                    resp.Serialize(&send_string);

                    // 5.添加报头并发送到网络
                    send_string = AddHeader(send_string);
                    send(sock, send_string.c_str(), send_string.size(), 0);
                }
            }
            close(sock);
        }

    private:
        uint16_t _port;
        Sock _listensock;
        func_t _func;
    };
}